<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      WCF中的異步調用

      WCF Tips之四

      WCF與Web Service不同的是,當我們定義了服務契約的操作時,不管是通過ChannelFactory創建服務代理對象,還是通過SvcUtil的默認方式生成服務代理對象,客戶端在調用這些代理對象時,都無法直接實現異步方式的調用。例如,對于如下的服務操作定義:
      [OperationContract]
      Stream TransferDocument(Document document);

      在調用代理對象的方法時,我們無法找到對應于TransferDocument()操作的BeginTransferDocument()和EndTransferDocument()異步方法。

      這樣的設計使得我們無法通過編程方式異步地調用服務的操作,除非我們在定義服務接口時,直接加入相關操作的異步方法。然而,這又直接導致了服務的設計與方法調用方式之間的耦合。一個好的框架設計要素在于,不管客戶端的調用方式(同步或者異步),服務的設計與實現應該是一致的。對于服務的設計者而言,在設計之初,就不應該去考慮服務的調用者調用的方式。換言之,服務操作究竟是否采用異步方式,應該由客戶端的調用者決定。因此,所有與異步調用相關的內容應該只與客戶端相關。WCF遵循了這一規則。

      在我編寫的應用程序中,會暴露一個傳送文檔文件的服務操作。我并不知道也并不關心調用該操作的客戶端是否采用異步方式。因此,如上所述的服務操作定義是完全正確的。

      那么,客戶端究竟應該如何執行異步調用呢?如果采用編程方式獲得服務代理對象,這一問題會變得比較糟糕。因為我將服務契約的定義單獨形成了一個程序集,并在客戶端直接引用了它。然而,在這樣的服務契約程序集中,是沒有包含異步方法的定義的。因此,我需要修改在客戶端的服務定義,增加操作的異步方法。這無疑為服務契約的重用帶來障礙。至少,我們需要在客戶端維持一份具有異步方法的服務契約。

      所幸,在客戶端決定采用異步方式調用我所設計的服務操作時,雖然需要修改客戶端的服務契約接口,但并不會影響服務端的契約定義。因此,服務端的契約定義可以保持不變,而在客戶端則修改接口定義如下:
          [ServiceContract]
          
      public interface IDocumentsExplorerService
          {
              [OperationContract]
              Stream TransferDocument(Document document);

              [OperationContract(AsyncPattern 
      = true)]
              IAsyncResult BeginTransferDocument(Document document,
                                                   AsyncCallback callback, 
      object asyncState);

              Stream EndTransferDocument(IAsyncResult result);
          } 

      注意,在BeginTransferDocument()方法上,必須在OperationContractAttribute中將AsyncPattern屬性值設置為true,因為它的默認值為false。

      調用方式如下:
      BasicHttpBinding binding = new BasicHttpBinding();
      binding.SendTimeout 
      = TimeSpan.FromMinutes(10);
      binding.TransferMode 
      = TransferMode.Streamed;
      binding.MaxReceivedMessageSize 
      = 9223372036854775807;

      EndpointAddress address 
      = new EndpointAddress
          (
      "http://localhost:8008/DocumentExplorerService");

      ChannelFactory
      <IDocumentsExplorerService> factory =
          new
       ChannelFactory<IDocumentsExplorerService>(binding,address);

      m_service 
      = factory.CreateChannel();

      ……
      IAsyncResult result 
      = m_service.BeginTransferDocument(doc,null,null);
      result.AsyncWaitHandle.WaitOne();
      Stream stream 
      = m_service.EndTransferDocument(result);

      如果采用SvcUtil生成客戶端代理文件,可以有更好的方式實現異步,也就是使用SvcUtil的/async開關,例如:
      svcutil /async http://localhost:8008/DocumentExplorerService

      唯一不足的是,它會不分青紅皂白,為所有服務操作都生成對應的異步方法。這樣的做法未免過于武斷。

      合理地利用服務的異步調用,可以有效地提高系統性能,合理分配任務的執行。特別對于UI應用程序而言,可以提高UI的響應速度,改善用戶體驗。在我編寫的應用程序中,下載的文件如果很大,就有必要采用異步方式。

      對于異步調用的完成,雖然WCF提供了諸如阻塞、
      等待輪詢等機制,但最好的方式還是使用回調。也就是利用Begin方法參數中的AsyncCallback對象。這是一個委托對象,它的定義如下所示:
      public delegate void AsyncCallback(IAsyncResult ar);

      利用異步方式執行服務操作,使得服務在執行過程中不會阻塞主線程,當方法執行完成后,通過AsyncCallback回調對應的方法,可以通知客戶端服務執行完畢。例如:
      //Invoke it Asynchronously
      m_service.BeginTransferDocument(m_doc,OnTransferCompleted,null);

      //Do some work;


      //callback method
      void OnTransferCompleted(IAsyncResult result)
      {
          Stream stream 
      = m_service.EndTransferDocument(result);
          result.AsyncWaitHandle.Close();

          lbMessage.Text 
      = string.Format("The file {0} had been transfered sucessfully.",
                                             m_doc.FileName);
      }

      在調用BeginTransferDocument()方法之后,主線程不會被阻塞,仍然可以繼續執行其它工作。而當服務方法執行完畢之后,會自動調用回調方法,執行方法中的內容。

      上述實現存在一個問題,就是對于lbMessage控件的操作。由于回調方法并非運行在主線程中,如果回調方法需要更新與異步調用結果相關的界面,例如本例中的lbMessage控件,則需要將回調的調用封送(Marshal)到當前主程序界面的同步上下文中。我們可以使用SynchronizationContext以及它的SendOrPostCallback委托,對調用進行封送:
      public ExplorerClientForm()
      {
          InitializeComponent();
          m_synchronizationContext 
      = SynchronizationContext.Current;
      }

      private SynchronizationContext m_synchronizationContext;

      則回調方法修改為:
      //callback method
      void OnTransferCompleted(IAsyncResult result)
      {
          Stream stream 
      = m_service.EndTransferDocument(result);
          result.AsyncWaitHandle.Close();

          SendOrPostCallback callback 
      = delegate
          {
              lbMessage.Text 
      = string.Format("The file {0} had been transfered sucessfully.",
                                                m_doc.FileName);
          };
          m_synchronizationContext.Send(callback,
      null);
      }

      在調用異步方法時,由于對Begin
      TransferDocument()和EndTransferDocument()方法的調用可能會在不同的方法體中,因而我將服務代理對象定義為private字段。如果希望將服務對象定義為一個局部變量,可以在調用BeginTransferDocument()方法時,將代理對象傳遞到方法的asyncState參數中,然后在調用EndTransferDocument()方法之前,通過IAsyncResult獲得準確的服務代理對象:
      m_service.BeginTransferDocument(m_doc,OnTransferCompleted,m_service);

      將m_service作為asyncState對象傳入之后,在調用EndTransferDocument()方法之前,就可以根據它先獲得服務代理對象:
      IDocumentsExplorerService m_service = result.AsyncState as IDocumentsExplorerService;
      Stream stream 
      = m_service.EndTransferDocument(result);
      //rest codes
      posted @ 2007-11-09 13:20  張逸  閱讀(11003)  評論(4)    收藏  舉報
      主站蜘蛛池模板: 特级欧美AAAAAAA免费观看| 精品国产乱码久久久久app下载| 午夜毛片精彩毛片| 国产精品亚洲一区二区z| 久久精品国产6699国产精| 日韩人妻无码精品专区综合网 | 中文字幕免费一二三区乱码| 亚洲精品美女一区二区| 国产香蕉久久精品综合网| 国产性三级高清在线观看| 日本免费观看mv免费版视频网站| 久久国产精品亚洲精品99| 国产男女猛烈无遮挡免费视频| 国产精品v欧美精品∨日韩| 综合图区亚洲另类偷窥| AV最新高清无码专区| 久久精产国品一二三产品| 大肉大捧一进一出好爽视频动漫| 亚洲天天堂天堂激情性色| 土默特右旗| 国产AV福利第一精品| 亚洲狠狠婷婷综合久久久| 国产高潮视频在线观看| 高潮精品熟妇一区二区三区| 丁香五月亚洲综合在线| 亚洲一级特黄大片在线观看| 亚洲av无码之国产精品网址蜜芽| 可以在线观看的亚洲视频| 99久久亚洲综合精品成人网| 成人午夜视频在线| 亚洲综合网一区中文字幕| 无码专区视频精品老司机| 老司机亚洲精品一区二区| 免费吃奶摸下激烈视频| 国产果冻豆传媒麻婆精东| 97免费在线观看视频| 日韩人妻无码一区二区三区| av天堂午夜精品一区| 亚洲精品无码av天堂| 亚洲欧美综合人成在线| 女厕偷窥一区二区三区|